/**
 * 加法
 * @param arg
 */
Number.prototype.add = function (arg) {
	let r1, r2, m
	try {
		r1 = this.toString().split('.')[1].length
	} catch (e) {
		r1 = 0
	}
	try {
		r2 = arg.toString().split('.')[1].length
	} catch (e) {
		r2 = 0
	}
	m = Math.pow(10, Math.max(r1, r2))
	// @ts-ignore
	return (this * m + arg * m) / m
}

/**
 * 减法
 * @param arg
 */
Number.prototype.sub = function (arg) {
	return this.add(-arg)
}

/**
 * 乘法
 * @param arg
 */
Number.prototype.mul = function (arg) {
	let m = 0, s1 = this.toString(), s2 = arg.toString()
	try {
		m += s1.split('.')[1].length
	} catch (e) {
	}
	try {
		m += s2.split('.')[1].length
	} catch (e) {
	}
	return Number(s1.replace('.', '')) * Number(s2.replace('.', '')) / Math.pow(10, m)
}

/**
 * 除法
 * @param arg
 */
Number.prototype.div = function (arg) {
	let t1 = 0, t2 = 0, r1, r2
	try {
		t1 = this.toString().split('.')[1].length
	} catch (e) {
	}
	try {
		t2 = arg.toString().split('.')[1].length
	} catch (e) {
	}
	r1 = Number(this.toString().replace('.', ''))
	r2 = Number(arg.toString().replace('.', ''))
	return (r1 / r2) * Math.pow(10, t2 - t1)
}

/**
 * 取模
 * @param arg
 */
Number.prototype.mod = function (arg) {
	// 先做除法，取商的整数部分
	const integerPart = Math.floor(this.div(arg))
	// 再用商的整数部分乘以除数，得到乘积
	const mul = integerPart.mul(arg)
	// 再用被除数减去乘积，得到余数
	return this.sub(mul)
}

// vue
import {createApp, type DirectiveBinding} from 'vue'
import App from '@/App.vue'
// pinia
import pinia from '@/stores/index'
// router
import router from '@/router'
import '@/router/router-guard'
// css
import '@/styles/index.scss'
// element-plus
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import 'element-plus/theme-chalk/display.css'
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
// mitt
import '@/utils/eventBusUtil'
// 全屏插件
import screenFull from 'screenfull'
// 图标样式
import '@/assets/icons/iconfont/iconfont.css'
import '@/assets/icons/awesome/font-awesome.min.css'
// i18n
import {loadLang} from '@/lang'
// ckeditor5（富文本编辑器）
import 'ckeditor5/ckeditor5.css'
import {CkeditorPlugin} from '@ckeditor/ckeditor5-vue'
// 其他
import {useNavTabsStore} from '@/stores/modules/navTabs.store'
import {useWebConfigStore} from '@/stores/modules/webConfig.store'
import {useEventListener} from '@vueuse/core'
import {hasPermission} from '@/utils/authUtil'

const initialize = () => {
	const app = createApp(App)

	app.use(pinia)

	// 全局语言包加载（要位于路由初始化之前）
	const i18n = loadLang(useWebConfigStore().lang.defaultLang, app)

	app.use(ElementPlus, <AnyObject>{i18n: i18n.global.t})

	app.use(router)

	for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
		app.component(`el-icon-${key}`, component)
	}

	app.use(CkeditorPlugin)

	// 注册全屏切换回调
	screenFull.onchange(() => {
		useNavTabsStore().tabFullScreen = screenFull.isFullscreen
		// resize
		setTimeout(() => {
			window.dispatchEvent(new Event('resize'))
		}, 200)
	})

	// 注册自定义指令
	// 权限控制：v-auth
	app.directive('auth', {
		beforeMount: (el, binding) => {
			if (!hasPermission(binding.value)) {
				el.disabled = true
				el.classList.add('is-disabled')
			}
		},
		beforeUpdate: (el, binding) => {
			if (!hasPermission(binding.value)) {
				el.disabled = true
				el.classList.add('is-disabled')
			}
		}
	})

	// 点击后自动失焦：v-blur
	app.directive('blur', {
		mounted(el) {
			useEventListener(el, 'focus', () => el.blur())
		}
	})

	// 点击外部：v-click-outside
	app.directive('click-outside', {
		beforeMount(el: HTMLElement, binding: DirectiveBinding) {
			let isMouseDownOutside = false
			el.clickOutsideEvent = (event: MouseEvent) => {
				if (!(el === event.target || el.contains(event.target as Node))) {
					isMouseDownOutside = true
				}
			}
			el.mouseUpOutsideEvent = (event: MouseEvent) => {
				if (isMouseDownOutside && !(el === event.target || el.contains(event.target as Node))) {
					binding.value(event, el)
				}
				isMouseDownOutside = false
			}
			setTimeout(() => {
				document.body.addEventListener('mousedown', el.clickOutsideEvent)
				document.body.addEventListener('mouseup', el.mouseUpOutsideEvent)
			}, 200)
		},
		unmounted(el: HTMLElement) {
			document.body.removeEventListener('mousedown', el.clickOutsideEvent)
			document.body.removeEventListener('mouseup', el.mouseUpOutsideEvent)
		}
	})

	// 跟随页面一起滚动：v-scroll-follow
	app.directive('scroll-follow', {
		mounted(el: HTMLElement, binding: DirectiveBinding) {
			const offset = binding.value || 0
			const onScroll = () => {
				const scrollTop = window.pageYOffset || document.documentElement.scrollTop
				el.style.transform = `translateY(${scrollTop + offset}px)`
			}
			window.addEventListener('scroll', onScroll)
			el._onScroll = onScroll
		},
		unmounted(el: HTMLElement) {
			window.removeEventListener('scroll', el._onScroll)
		}
	})

	app.mount('#app')

	return app
}

const MyApp = initialize()

export default MyApp
